#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "senwordtrie.h"

SenWordTrie::SenWordTrie_node::SenWordTrie_node() 
{
	senWordData = NULL;
	level = 0;
	is_sensitive_word = false;
	for (int i=0; i<num_chars; ++i) 
	{
		branch[i] = NULL;
	}
}

SenWordTrie::SenWordTrie_node::~SenWordTrie_node() 
{
	if( this->is_sensitive_word )
	{
		free( senWordData );
		senWordData = NULL;
	}
}

SenWordTrie::SenWordTrie():m_root(NULL)
{
    m_memorySize = 0;
    m_nodeCounts = 0;
}

SenWordTrie::~SenWordTrie()
{
	m_root = NULL;
	for( list<SenWordTrie_node*>::iterator it=this->m_lNodes.begin(); it!=this->m_lNodes.end(); ++it )
	{
		delete (SenWordTrie_node*)(*it);
	}
}

/*
 * match the sensitive word in sensitiveword tree
 * return value:
 * 	szRetSenWord: if return value is 0, the point to the sensitive word, else assign NULL
 * int return:
 * 	0: is sensitive word
 * 	<0: not sensitive word
 * */
int SenWordTrie::trie_search(const char* word, unsigned int uiSearchLen, char ** szRetSenWord) const 
{
	const char * char_code = word;
	unsigned int iPos = 0;
	SenWordTrie_node *location = this->m_root;
	*szRetSenWord = NULL;

	for( ;location!=NULL && *char_code!=0 && iPos<uiSearchLen; ++iPos ) 
	{
		if( location->branch[(unsigned char)(*char_code)]!=NULL )
		{
			location = location->branch[(unsigned char)(*char_code)];
			if( location->is_sensitive_word )
			{
				//printf( "found.\n" );
				*szRetSenWord = location->senWordData;
				return 0;
			}

			char_code++;
		}
		else
		{
			return -1;
		}
	}

	if( location==NULL )
	{
		return -1;
	}
	else if( iPos>=uiSearchLen )
	{
		return -2;
	}
	return -3;
}

int SenWordTrie::querySenWord(const char * srcContent, char **szRetSenWord) const
{
	int iContentLen = 0;
	int iRet = 0;
	iContentLen = strlen( srcContent );
	if( iContentLen==0 ) 
	{
		return -1;
	}

	const char * szPosContent = srcContent;
	for( int i=0; *szPosContent!=0 && i<iContentLen; ++i )
	{
		//printf( "search sensitive word:[%d][%s]\n", iContentLen-i, szPosContent );
		iRet = this->trie_search( szPosContent, iContentLen-i, szRetSenWord ); 
		if( iRet==0 )
		{
			return 0;
		}
		szPosContent++;
	}
	return -1;
}

/*return replace sensitive word counts
 * return value: >0, has sensitive word replace
 *               <0, no sensitive word replace
 * */
int SenWordTrie::replaceSenWord(char * srcContent) 
{
	int iContentLen = 0;
	int iRet = 0;
    int iFlag = 0;
	iContentLen = strlen( srcContent );
	if( iContentLen==0 ) 
	{
		return -1;
	}

    char * szRetSenWord = NULL;
    int iCurSenWordLen = 0;
    int iCurSenWordLenSave = 0;
	char * szPosContent = srcContent;
	for( int i=0; *szPosContent!=0 && i<iContentLen; ++i )
	{
		//printf( "search sensitive word:[%d][%s]\n", iContentLen-i, szPosContent );
		iRet = this->trie_search( szPosContent, iContentLen-i, &szRetSenWord ); 
		if( iRet==0 )
		{
            iCurSenWordLenSave = iCurSenWordLen = strlen(szRetSenWord);
            iFlag++;
			while( iCurSenWordLen-->0 )
            {
                szPosContent[iCurSenWordLen] = '*';
            }
            szPosContent += iCurSenWordLenSave + 1;
		}
        else
        {
		    szPosContent++;
        }
	}

	return iFlag;
}

/*return replace sensitive word counts
 * return value: >0, has sensitive word replace
 *               <0, no sensitive word replace
 * */
int SenWordTrie::replaceSenWord2(char * srcContent) 
{
	int iContentLen = 0;
	int iRet = 0;
    int iFlag = 0;
	iContentLen = strlen( srcContent );
	if( iContentLen==0 ) 
	{
		return -1;
	}

    char * szCopySenword = new char[iContentLen+1];
    memset( szCopySenword, 0, iContentLen+1 );
    memcpy( szCopySenword, srcContent, iContentLen );

    char * szRetSenWord = NULL;
    int iCurSenWordLen = 0;
    int iCurSenWordLenSave = 0;
	char * szPosContent = szCopySenword;
	for( int i=0; *szPosContent!=0 && i<iContentLen; ++i )
	{
		//printf( "search sensitive word:[%d][%s]\n", iContentLen-i, szPosContent );
		iRet = this->trie_search( szPosContent, iContentLen-i, &szRetSenWord ); 
		if( iRet==0 )
		{
            iCurSenWordLenSave = iCurSenWordLen = strlen(szRetSenWord);
            iFlag++;
            if( iCurSenWordLen>3 )
            {
                memcpy( szPosContent, "***", 3 ); 
                memcpy( szPosContent+3, szPosContent+iCurSenWordLenSave, iContentLen-i-iCurSenWordLen );
                szPosContent[iContentLen-i-iCurSenWordLen+3] = 0;
                szPosContent += 3;
                iContentLen = strlen(szCopySenword);
            }
            else
            {
                while( iCurSenWordLen-->0 )
                {
                    szPosContent[iCurSenWordLen] = '*';
                }
                szPosContent += iCurSenWordLenSave + 1;
            }
		}
        else
        {
		    szPosContent++;
        }
	}

    memcpy( srcContent, szCopySenword, strlen(szCopySenword) );
    srcContent[strlen(szCopySenword)] = 0;
    if( szCopySenword ) delete [] szCopySenword;

	return iFlag;
}


void SenWordTrie::dump()
{
	if ( this->m_root == NULL )
	{
		printf( "not sensitive word in tree.\n" );	
		return;
	}

	/*SenWordTrie_node *location = this->m_root;
	for( int i=0; i<0xFF; ++i )
	{
		if( location!=NULL && );
	}
	*/
	for( list<SenWordTrie_node*>::iterator it=this->m_lNodes.begin(); it!=this->m_lNodes.end(); ++it )
	{
		if( (*it) !=NULL && (*it)->is_sensitive_word )
		{
			printf( "%s\t", (*it)->senWordData );
		}
	}
}

int SenWordTrie::insert(const char* word) 
{
	int iSrcLen = 0;
	iSrcLen = strlen( word );
	if( iSrcLen==0 )
	{
		return -1;
	}

	if ( this->m_root == NULL )
	{
		this->m_root = new SenWordTrie_node;
        //debug memory size*****************
        this->m_nodeCounts += 1;
	}

	//int result = 1, position = 0;
	const char * char_code = word;
	SenWordTrie_node *location = this->m_root;

	for( int i=0; i<iSrcLen && location!=NULL && *char_code!=0; ++i )
	{
		if( location->branch[(unsigned char)(*char_code)] == NULL ) 
		{
			SenWordTrie_node * newNode = new SenWordTrie_node;

            //debug memory size*****************
            this->m_nodeCounts += 1;

			this->m_lNodes.push_front(newNode);
			newNode->level = i;
			if( i==iSrcLen-1 )
			{
				newNode->is_sensitive_word = true;

				char * SenWord = (char*)malloc(iSrcLen+1);
				memcpy( SenWord, word, iSrcLen );
				SenWord[iSrcLen] = 0;
				newNode->senWordData = SenWord;
            
                //debug memory size*****************
                this->m_memorySize += iSrcLen+1;
				//printf( "insert a leaf sensitive word:%s\n", newNode->senWordData );
			}

			location->branch[(unsigned char)(*char_code)] = newNode;
		}
		location = location->branch[(unsigned char)(*char_code)];
		char_code++;
	}

	return 0;
}


 
